# This file is part of the Net::Tube module.
#
# Net::Tube is Free Software; you can use, redistribute it and/or
# modify it under the terms of either:
#
# a) the GNU General Public License as published by the Free Software
#    Foundation, either version 2, or (at your opinion) any later
#    version, or
#
# b) the "Artistic License" which comes with Perl.
#
use Test::Simple tests => 29;

use Net::Tube;
use XML::LibXML;

sub test_new {
    my $b;

    $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        return 0;
    }
    return 1;
}
ok( test_new(), "new() test" );

sub test_format_output {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    unless ( defined $b->format_output() && $b->format_output() == 0 ) {
        print "# bucket has a broken default value\n";
        return 0;
    }

    $b->format_output(1);
    unless ( defined $b->format_output && $b->format_output == 1 ) {
        print "# bucket did not set the new value \n";
        return 0;
    }
    $b->format_output(0);
    unless ( $b->format_output == 0 ) {
        print "# bucket did not reset the new value \n";
        return 0;
    }
    $b->format_output(1);
    $b->format_output(undef);
    unless ( defined $b->format_output && $b->format_output == 0 ) {
        print "# bucket did not set undef properly to zero\n";
        return 0;
    }

    return 1;
}
ok( test_format_output(), "output formatting option" );

sub test_initial_counting {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    unless ( $b->count == 0 ) {
        print "# bucket does not count properly by default\n";
        return 0;
    }
    return 1;
}
ok( test_initial_counting(), "test node counting on empty list" );

sub test_add_node {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $n = XML::LibXML::Element->new("test");
    unless ( defined $n ) {
        print "# failed to create a node\n";
        return 0;
    }
    $b->add_node($n);
    unless ( $b->count == 1 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( $n->isSameNode($t) ) {
        print "# something strange has happened\n";
        return 0;
    }
    return 1;
}

ok( test_add_node(), 'test node adding and counting on non-empty list' );

sub test_add_xml_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xml = "<a/>";
    $b->add_xml($xml);
    unless ( $b->count == 1 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "a" )
    {
        print "# wrong data ended up in the document\n";
        return 0;
    }
    return 1;
}
ok( test_add_xml_01(), 'add only one XML document to the bucket' );

sub test_add_xml_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }

    my $x1 = "<a/>";
    my $x2 = "<b/>";
    $b->add_xml($x1);
    $b->add_xml($x2);
    unless ( $b->count == 2 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "a" )
    {
        print "# wrong data ended up in the first document\n";
        return 0;
    }

    $t = $b->get_node(1);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "b" )
    {
        print "# wrong data ended up in the second document\n";
        return 0;
    }

    return 1;
}
ok( test_add_xml_02(), 'add more than one XML document to the bucket' );

sub test_add_json_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $j1 = '{"a":"b"}';
    $b->add_json($j1);
    unless ( $b->count == 1 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "data" )
    {
        print "# wrong data ended up in the document\n";
        return 0;
    }

    my $a = $t->documentElement->firstChild;
    unless ( defined $a && $a->nodeName eq "a" && $a->textContent eq "b" ) {
        print "# wrong data ended up in the docuent\n";
        return 0;
    }

    return 1;
}
ok( test_add_json_01(), 'add only one JSON document to the bucket' );

sub test_add_json_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $j1 = '{"a":"b"}';
    my $j2 = '{"b":"a"}';
    $b->add_json($j1);
    $b->add_json($j2);
    unless ( $b->count == 2 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "data" )
    {
        print "# wrong data ended up in the document\n";
        return 0;
    }

    my $a = $t->documentElement->firstChild;
    unless ( defined $a && $a->nodeName eq "a" && $a->textContent eq "b" ) {
        print "# wrong data ended up in the docuent\n";
        return 0;
    }

    $t = $b->get_node(1);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "data" )
    {
        print "# wrong data ended up in the document\n";
        return 0;
    }

    $a = $t->documentElement->firstChild;
    unless ( defined $a && $a->nodeName eq "b" && $a->textContent eq "a" ) {
        print "# wrong data ended up in the docuent\n";
        return 0;
    }
    return 1;
}
ok( test_add_json_02(), 'add more than one JSON document to the bucket' );

sub test_add_object_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $j1 = {a=>'b'};
    $b->add_object($j1);
    unless ( $b->count == 1 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t = $b->get_node(0);
    unless ( defined $t
        && $t->documentElement
        && $t->documentElement->nodeName eq "data" )
    {
        print "# wrong data ended up in the document\n";
        return 0;
    }

    my $a = $t->documentElement->firstChild;
    unless ( defined $a && $a->nodeName eq "a" && $a->textContent eq "b" ) {
        print "# wrong data ended up in the docuent\n";
        return 0;
    }

    return 1;
}
ok( test_add_object_01(), 'add a perl object to the bucket' );

sub test_get_node_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $t = $b->get_node(0);
    if ( defined $t ) {
        print "#weired things happen!\n";
        return 0;
    }
    return 1;
}
ok( test_get_node_01(), 'node getter on empty list' );

sub test_get_node_04 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }

    my $x1 = "<a/>";
    my $x2 = "<b/>";
    $b->add_xml($x1);
    $b->add_xml($x2);
    unless ( $b->count == 2 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t;

    # lower bounds
    $t = $b->get_node(undef);
    if ( defined $t ) {
        print "# lower bounds not recognised\n";
        return 0;
    }

    # upper bounds
    $t = $b->get_node(2);
    if ( defined $t ) {
        print "# upper bounds not recognised\n";
        return 0;
    }

    return 1;
}
ok( test_get_node_04(),
    'node getter on multiple entry list out of boundaries' );

sub test_get_node_05 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }

    my $x1 = "<a/>";
    my $x2 = "<b/>";
    $b->add_xml($x1);
    $b->add_xml($x2);
    unless ( $b->count == 2 ) {
        print "# invalid count\n";
        return 0;
    }

    my $t;

    # lower bounds
    $t = $b->get_node(-1);
    if ( defined $t ) {
        print "# lower bounds not recognised\n";
        return 0;
    }

    return 1;
}
ok( test_get_node_05(),
    'node getter on multiple entry list using invalid value (less zero)' );

sub test_node_list_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $nl = $b->node_list();
    unless ( defined $nl ) {
        print "# no nodelist has been returned\n";
        return 0;
    }
    unless ( $nl->size == 0 ) {
        print "# wrong number of elements found in the node list\n";
        return 0;
    }

    return 1;
}
ok( test_node_list_01(), 'fetch nodelist from an empty bucket' );

sub test_node_list_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $x1 = "<a/>";
    my $x2 = "<b/>";
    $b->add_xml($x1);
    $b->add_xml($x2);
    unless ( $b->count == 2 ) {
        print "# invalid count\n";
        return 0;
    }
    my $nl = $b->node_list();
    unless ( defined $nl ) {
        print "# no nodelist has been returned\n";
        return 0;
    }
    unless ( $nl->size == 2 ) {
        print "# wrong number of elements found in the node list\n";
        return 0;
    }

    return 1;
}
ok( test_node_list_02(), 'fetch nodelist from an filled bucket' );

sub test_dump_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $d = $b->dump;
    unless ( defined $d && length $d == 0 ) {
        print "# dump failed\n";
    }
    return 1;
}
ok( test_dump_01(), 'dump data on empty bucket' );

sub test_dump_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $x1 = "<?xml version=\"1.0\"?>\n<a/>\n";
    $b->add_xml($x1);
    my $d = $b->dump;
    unless ( defined $d && length $d ) {
        print "# dump failed\n";
        return 0;
    }
    unless ( $d eq $x1 ) {
        print "# wrong data dumped ($d)\n";
        return 0;
    }
    return 1;
}
ok( test_dump_02(), 'dump data on single entry bucket' );

sub test_dump_03 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }

    my $x1 = "<?xml version=\"1.0\"?>\n<a/>\n";
    my $x2 = "<?xml version=\"1.0\"?>\n<b/>\n";
    $b->add_xml($x1);
    $b->add_xml($x2);
    my $d = $b->dump;
    unless ( defined $d && length $d ) {
        print "# dump failed\n";
        return 0;
    }
    unless ( $d eq $x1. $x2) {
        print "# wrong data dumped ($d)\n";
        return 0;
    }
    return 1;
}
ok( test_dump_03(), 'dump data on multiple entry bucket' );

sub test_dump_04 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    
    $b->format_output(1);
    $b->add_xml('<a><b/></a>');
    my $d = $b->dump;
    unless ( defined $d && length $d ) {
        print "# dump failed\n";
        return 0;
    }
    my $xml = "<?xml version=\"1.0\"?>\n<a>\n  <b/>\n</a>\n";
    unless ($d eq $xml) {
        print "#dumped wrong data ($d)\n";
        return 0;
    }
    return 1;
}
ok( test_dump_04(), 'formatted dump data on a single entry bucket' );

sub test_dump_05 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    $b->format_output(1);
    $b->add_xml('<a><b/></a>');
    $b->add_xml('<c><b/></c>');
    my $d = $b->dump;
    unless ( defined $d && length $d ) {
        print "# dump failed\n";
        return 0;
    }
    my $xml = "<?xml version=\"1.0\"?>\n<a>\n  <b/>\n</a>\n";
    $xml .= "<?xml version=\"1.0\"?>\n<c>\n  <b/>\n</c>\n";
    unless ($d eq $xml) {
        print "#dumped wrong data ($d)\n";
        return 0;
    }
    return 1;    
}
ok( test_dump_05(), 'formatted dump data on a multiple entry bucket' );

sub test_find_nodes_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//a';
    my $nl = $b->find_nodes($xp);
    unless ( defined $nl ) {
        print "# no node list has been returned!\n";
        return 0;
    }

    unless ( scalar @$nl == 0 ) {
        print "# function added data!?\n";
        return 0;
    }

    return 1;
}
ok( test_find_nodes_01(), 'find nodes on an empty bucket' );

sub test_find_nodes_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    $b->add_xml("<a>b</a>");
    my $xp = '//a';
    my $nl = $b->find_nodes($xp);
    unless ( defined $nl ) {
        print "# no node list has been returned!\n";
        return 0;
    }

    unless ( scalar @$nl == 1 ) {
        print "# ONLY ONE node should be found\n";
        return 0;
    }

    return 1;
}
ok( test_find_nodes_02(),
    'find nodes on a single entry bucket single DOM match' );

sub test_find_nodes_03 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }

    $b->add_xml("<b><a>b</a><a>C</a></b>");
    $b->add_xml("<B>b</B>");
    my $xp = '//a';
    my $nl = $b->find_nodes($xp);
    unless ( defined $nl ) {
        print "# no node list has been returned!\n";
        return 0;
    }

    unless ( scalar @$nl == 2 ) {
        print "# two nodes should be found\n";
        return 0;
    }

    return 1;
}
ok( test_find_nodes_03(),
    'find nodes on a multiple entry bucket single DOM match' );

sub test_find_nodes_04 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    $b->add_xml("<a>b</a>");
    $b->add_xml("<b><a>b</a></b>");
    my $xp = '//c';
    my $nl = $b->find_nodes($xp);
    unless ( defined $nl ) {
        print "# no node list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 0 ) {
        print "# no nodes should be found\n";
        return 0;
    }
    return 1;
}
ok( test_find_nodes_04(), 'find nodes on a multiple entry bucket no match' );

sub test_find_nodes_05 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//a';
    $b->add_xml("<a>b</a>");
    $b->add_xml("<b><a>b</a></b>");

    my $nl = $b->find_nodes($xp);
    unless ( defined $nl ) {
        print "# no node list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 2 ) {
        print "# two nodes should be found\n";
        return 0;
    }
    return 1;
}
ok( test_find_nodes_05(),
    'find nodes on a multiple entry bucket multi DOM match' );

sub test_find_value_01 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//a';
    my $nl = $b->find_values($xp);
    unless ( defined $nl ) {
        print "# no value list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 0 ) {
        print "# no values should be found\n";
        return 0;
    }
    return 1;
}
ok( test_find_value_01(), 'find value on an empty bucket' );

sub test_find_value_02 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    $b->add_xml("<a>b</a>");
    my $xp = '//a';
    my $nl = $b->find_values($xp);
    unless ( defined $nl ) {
        print "# no value list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 1 ) {
        print "# only a single value should have been found\n";
        return 0;
    }
    unless ( $nl->[0] eq 'b' ) {
        print "# wrong value has been returned\n";
        return 0;
    }

    return 1;
}
ok( test_find_value_02(),
    'find value on a single entry bucket single DOM match' );

sub test_find_value_03 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//a';
    $b->add_xml("<a>b</a>");
    $b->add_xml("<b>c</b>");
    my $nl = $b->find_values($xp);
    unless ( defined $nl ) {
        print "# no value list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 1 ) {
        print "# only a single value should have been found\n";
        return 0;
    }
    unless ( $nl->[0] eq 'b' ) {
        print "# wrong value has been returned\n";
        return 0;
    }
    return 1;
}
ok( test_find_value_03(),
    'find value on a multiple entry bucket single DOM match' );

sub test_find_value_04 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//c';
    $b->add_xml("<a>b</a>");
    $b->add_xml("<b>b</b>");
    my $nl = $b->find_values($xp);
    unless ( defined $nl ) {
        print "# no value list has been returned!\n";
        return 0;
    }
    unless ( scalar @$nl == 0 ) {
        print "# no values should be found\n";
        return 0;
    }
    return 1;
}
ok( test_find_value_04(), 'find value on a multiple entry bucket no match' );

sub test_find_value_05 {
    my $b = Net::Tube::Bucket->new();
    unless ( defined $b ) {
        print "# failed to create a bucket\n";
        return 0;
    }
    my $xp = '//a';
    $b->add_xml("<a>b</a>");
    $b->add_xml("<b><a>c</a></b>");
    my $nl = $b->find_values($xp);
    unless ( defined $nl ) {
        print "# no value list has been returned!\n";
        return 0;
    }

    unless ( scalar @$nl == 2 ) {
        print "# two values should be found\n";
        return 0;
    }

    unless ( $nl->[0] eq 'b' ) {
        print "# first value is wrong \n";
        return 0;
    }
    unless ( $nl->[1] eq 'c' ) {
        print "# second value is wrong \n";
        return 0;
    }
    return 1;
}
ok( test_find_value_05(),
    'find value on a multiple entry bucket multi DOM match' );

